﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GcmpModelInterface.h"
#include "Box3d.h"
#include "BodiesPositionTypes.h"
#include "GraphicsNodeId.h"
#include "GcmpApiDeclaration.h"
#include "BodyTopologyOperateData.h"

namespace gcmp
{
    class IDocument;
    class IGraphicsNode;
    class IGraphicsBRepBody;
    class IGraphicsMeshBody;
    class IGraphicsElementShape;
    class IGraphicsBRepFace;
    class IGraphicsPlane;
    class Matrix4d;
    struct GraphicsNodeAndTransform;

    /// \brief 与图形节点相关的一些工具函数
    class GCMP_MODEL_INTERFACE_EXPORT GraphicsNodeUtils
    {
    public:
        /// \brief 得到两个element图形表达的位置关系类型 
        ///  只拿出pFirstGraphicsElementShape与pSecondGraphicsElementShape中体计算他们的位置关系类型
        /// \param pDocument 文档指针
        /// \param pFirstGraphicsElementShape element图形表达指针
        /// \param pSecondGraphicsElementShape element图形表达指针 
        /// \return 返回其关系类型
        static BodiesPositionTypes GetBodiesPositionType(const IDocument* pDocument, const IGraphicsElementShape* pFirstGraphicsElementShape, const IGraphicsElementShape *pSecondGraphicsElementShape);

        /// \brief 得到两个体的位置关系类型
        /// \param pFirstGraphicsBRepBody 体图形节点
        /// \param pSecondGraphicsBRepBody 体图形节点 
        /// \return 返回两个体关系类型
        static BodiesPositionTypes GetBodiesPositionType(const IGraphicsBRepBody* pFirstGraphicsBRepBody, const IGraphicsBRepBody *pSecondGraphicsBRepBody);

        /// \brief 得到element图形表达下面的所有体
        /// \param pDocument 文档指针
        /// \param pGraphicsElementShape element图形表达指针
        /// \return  返回element图形表达下面的所有体
        static std::vector<OwnerPtr<IGraphicsBRepBody>> GetGraphicsBRepBodies(const IDocument* pDocument, const IGraphicsElementShape* pGraphicsElementShape);

        /// \brief 对两个element图形表达数据进行消隐
        /// 目前只会拿element图形显示数据的一个体进行消隐
        /// \param pDocument 文档指针
        /// \param pFirstGraphicsElementShape element图形表达指针
        /// \param pSecondGraphicsElementShape element图形表达指针
        /// \param isKeepOrigEdgeId 消隐打断新生成的边的id是否保留原来的id，默认保留 
        /// \return 返回true表示成功，返回false表示失败。
        static bool HideGraphicsElementShapeEdges(const IDocument* pDocument, const IGraphicsElementShape *pFirstGraphicsElementShape, const IGraphicsElementShape *pSecondGraphicsElementShape, bool isKeepOrigEdgeId = true);

        /// \brief 实时计算图形节点的包围盒
        /// \param pDoc 文档
        /// \param pGraphicsNode 图形节点
        /// \return 图形节点的包围盒
        static Box3d CalculateGraphicsNodeBoundingBox(const IDocument* pDocment, const IGraphicsNode* pGraphicsNode);

        /// \brief 收集图形表达节点里面的所有BREP体节点
        /// \param pDocument 文档
        /// \param pGraphicsElementShape 图形表达节点
        /// \param pBodies 指向用于返回的BREP体节点容器的指针，指针不能为空
        /// \param pTransforms 指向用于返回的变换矩阵容器的指针，指针不能为空
        /// \param pPaths 指向用于返回的节点路径容器的指针，指针可以为空
        /// \return 无
        static void CollectBRepBodies(const IDocument* pDocument
            , const IGraphicsElementShape* pGraphicsElementShape
            , std::vector<const IGraphicsBRepBody*>* pBodies
            , std::vector<Matrix4d>* pTransforms
            , std::vector<std::vector<const IGraphicsNode*>>* pPaths = nullptr);

        /// \brief 收集图形表达节点里面的所有Mesh体节点
        /// \param pDocument 文档
        /// \param pGraphicsElementShape 图形表达节点
        /// \param pBodies 指向用于返回的Mesh体节点容器的指针，指针不能为空
        /// \param pTransforms 指向用于返回的变换矩阵容器的指针，指针不能为空
        /// \param pPaths 指向用于返回的节点路径容器的指针，指针可以为空
        /// \return 无
        static void CollectMeshBodies(const IDocument* pDocument
            , const IGraphicsElementShape* pGraphicsElementShape
            , std::vector<const IGraphicsMeshBody*>* pBodies
            , std::vector<Matrix4d>* pTransforms
            , std::vector<std::vector<const IGraphicsNode*>>* pPaths = nullptr);

        /// \brief 替换BREP形体
        /// \param pDocument 文档
        /// \param pGraphicsElementShape 被替换的图形表达节点
        /// \param bodyIndex 需要被替换的body索引
        /// \param opNewBody 用于替换的新Body
        /// \return true 替换成功，false 替换失败
        static bool ReplaceBRepBody(const IDocument* pDocument, IGraphicsElementShape* pGraphicsElementShape, int bodyIndex, OwnerPtr<IGraphicsBRepBody> opNewBody);

        /// \brief 根据八叉树得到在包围盒范围内的形体
        /// \param pDocument 文档
        /// \param box 包围盒
        /// \param graphicsElementShapesInBox 返回包围盒中的形体
        /// \return true 获取成功，false 获取失败
        static bool GetBRepsInBox(IDocument* pDocument, const Box3d& box, std::vector<const IGraphicsElementShape*>& graphicsElementShapesInBox);

        /// \brief 清除图形表达节点所有的材质及样式
        ////
        /// 会遍历图形表达节点下的所有节点，把样式和材质id设置为无效值
        /// \param pDocment 文档
        /// \param pGraphicsNode 图形表达节点
        /// \return 返回true表示成功，返回false表示失败
        static bool CleanGraphicsNodeStyleAndMaterial(IDocument* pDocment, IGraphicsNode* pGraphicsNode);

        /// \brief 利用八叉树查找与两点构造的线段有交的可见图形表达图形节点
        /// \param pDocument 文档
        /// \param startPoint 起点坐标
        /// \param endPoint 终点坐标
        /// \param graphicsElementShapes 与两点构造的线段有交的可见图形表达图形节点数组
        /// \param distanceTolerance 距离容差，以毫米为单位
        /// \return true-找到与两点构造的线段有交的可见图形表达图形节点；false-没找到与两点构造的线段有交的可见图形表达图形节点
        static bool FindVisibleModelGraphicsElementShapesByTwoPoints(const IDocument* pDocument, const Vector3d& startPoint, const Vector3d& endPoint, std::vector< const IGraphicsElementShape * >& graphicsElementShapes, double distanceTolerance);

        /// \brief 利用八叉树查找与三维包围盒有交或在包围盒内的可见图形表达图形节点
        /// \param pDocument 文档
        /// \param inputBox 三维包围盒
        /// \param graphicsElementShapes 与三维包围盒有交或在包围盒内的可见图形表达图形节点数组
        /// \return true-找到与三维包围盒有交或在包围盒内的可见图形表达图形节点；false-没找到与三维包围盒有交或在包围盒内的可见图形表达图形节点
        static bool FindVisibleModelGraphicsElementShapesByBox3d(const IDocument* pDocument, const Box3d &inputBox, std::vector< const IGraphicsElementShape * >& graphicsElementShapes);
        
        /// \brief 根据图形节点路径获取该节点上的带有变换矩阵的图形节点
        /// \param pDocument 文档
        /// \param pGraphicsNode 图形节点
        /// \param graphicsNodeIdPath 图形节点ID路径
        /// \return 该节点上的带有变换矩阵的图形节点
        static OwnerPtr<GraphicsNodeAndTransform> GetGraphicsNodeAndTransform(const IDocument* pDocument, const IGraphicsNode* pGraphicsNode, const std::vector<GraphicsNodeId>& graphicsNodeIdPath); 
    
        /// \brief 用特定平面剖切 Brep 形体
        /// \param pBrepBodyToSplit 待剖切的 Brep 形体
        /// \param pCutPlane 用于剖切的平面
        /// \param positiveBodyAndSectionFaces 平面法向正向的 Brep 形体及体上的剖切面
        /// \param negativeBodyAndSectionFaces 平面法向负向的 Brep 形体及体上的剖切面
        /// \param tolerance 容差，默认0.1
        /// \return EnPlaneSplitBodyResult 面裁体结果
        static EnPlaneSplitBodyResult SplitBRepBody(const IGraphicsBRepBody* pBrepBodyToSplit, const IGraphicsPlane* pCutPlane, std::pair<OwnerPtr<IGraphicsBRepBody>, std::vector<IGraphicsBRepFace*>>& positiveBodyAndSectionFaces, std::pair<OwnerPtr<IGraphicsBRepBody>, std::vector<IGraphicsBRepFace*>>& negativeBodyAndSectionFaces, double tolerance = 0.1);

        /// \brief 用特定平面剖切 Brep 形体
        /// \param pBrepBodyToSplit 待剖切的 Brep 形体
        /// \param pCutPlane 用于剖切的平面
        /// \param positiveBodyAndSectionFaces 平面法向正向的 Brep 形体及体上的剖切面
        /// \param negativeBodyAndSectionFaces 平面法向负向的 Brep 形体及体上的剖切面
        /// \param tolerance 容差，默认0.1
        /// \param ppPositiveGBody 传null则代表不需要切割面上面部分，传地址代表需要一分为二后的全部体
        /// \return EnPlaneSplitBodyResult 面裁体结果
        static EnPlaneSplitBodyResult SplitBRepBody(const IGraphicsBRepBody* pBrepBodyToSplit, const IGraphicsPlane* pCutPlane, std::pair<OwnerPtr<IGraphicsBRepBody>, std::vector<IGraphicsBRepFace*>>& positiveBodyAndSectionFaces, std::pair<OwnerPtr<IGraphicsBRepBody>, std::vector<IGraphicsBRepFace*>>& negativeBodyAndSectionFaces, OwnerPtr<IGraphicsBRepBody>* ppPositiveGBody, double tolerance = 0.1);
};
}





